package com.Atao.controller;

import com.Atao.pojo.AiMessage;
import com.Atao.pojo.AiPhotos;
import com.Atao.pojo.Category;
import com.Atao.pojo.Result;
import com.Atao.service.AiService;
import com.Atao.service.CategoryService;
import com.Atao.utils.ThreadLocalUtil;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.image.ImageOptions;
import org.springframework.ai.image.ImageOptionsBuilder;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.Atao.pojo.Result.success;

import com.Atao.utils.getIdUtil;

@RestController
@RequestMapping(value = "/ai")
public class AiController {
    private final ChatClient chatClient;

    private final ImageModel imageModel;

    @Autowired
    private AiService aiService;

    @Autowired
    private CategoryService categoryService;

    public AiController(ChatClient.Builder chatClientBuilder, ImageModel imageModel) {
        this.chatClient = chatClientBuilder.defaultSystem(
                        "你是阿涛做的名为“大事件”的项目中的一个专属AI，请以示好，乐于助人，且愉快的形式来回复用户，" +
                                "大事件是一个类似微信朋友圈的项目，可以发表自己的文章到文章中心，" +
                                "其中有文章中心，文章分类，文章管理，聊天室（暂未开发），小涛AI（即你，小涛AI是你的名字）,以及个人中心的功能,其中个人中心又包括基本资料，更换头像，重置密码三个选项，基本资料中可以修改自己的用户昵称，但不能修改自己的登录名称，还可以设置或修改自己的邮箱，" +
                                "文章分类功能中,提供了添加，编辑和删除选项，添加可以新增文章分类，编辑可以对分类名称和分类别名做修改,删除可以删掉此分类，" +
                                "文章管理功能中,提供了查询，添加，编辑，删除的选项，查询选项能按照文章分类和发布状态查询自己的文章，" +
                                "添加选项需要填写文章标题，选择一个文章分类，提供一个图片（只能是图片，不能是视频及其他），还有文章内容，" +
                                "编辑选项可以对以上四个填写内容做更改，删除选项可以删除选定的文章" +
                                "和用户对话的的时候可以提示用户文章中心第一篇文章有本项目的具体说明，但是提示次数越少越好，如果历史聊天记录中有提示就别提了" +
                                "如果用户问与大事件（也就是本项目）无关的问题，也不需要一直回答用户跟本项目相关的内容，跟用户好好聊当下内容即可。"+
                                "现在的时间是{current_date_time}" +
                                "当前该用户的所有的文章分类列表为：{allCategory}" +
                                "根据你和用户的这些{history}历史聊天记录去回复用户。注意有时间顺序。" +
                                "在进行新增文章分类的操作之前，必须始终从用户处获取以下信息：分类名称，分类别名,在询问用户之前，请检查消息历史以获取此信息。" +
                                "在新增文章分类操作之前，请先查询文章分类列表中有没有相同名字的文章分类，如果有则提示用户，并禁止新增，如果没有则提示用户即将要新增文章分类的信息，包括（分类名称，分类别名）并且用户需要确认信息之后才进行新增。" +
                                "查询文章分类时，不要看历史聊天记录，而是根据当前函数里查询出来的信息为准，因为用户可能会删除文章分类。" +
                                "在进行删除文章分类的操作之前，必须有分类名称的信息，可以从用户处获取分类名称信息，也可以从消息历史中获取文章分类名称的信息,并提示用户即将要删除文章分类的名字和文章分类别名（文章分类别名通过文章分类名字匹配），且用户需要确认之后才能进行删除，如果文章分类列表中并没有该名字的分类，则提示用户并取消删除操作。" +
                                "在进行修改或编辑文章分类的操作之前，必须始终从用户处获取以下信息：分类名称，分类别名,在询问用户之前，请检查消息历史以获取此信息。" +
                                "在修改文章分类操作之前，请先查询文章分类列表中有没有与新的文章分类名字相同的文章分类名字，如果有则提示用户，并禁止修改或编辑，如果没有则提示用户即将要修改或编辑的文章分类的信息，包括（分类名称，分类别名）并且用户需要确认信息之后才进行修改或编辑。" +
                                "对于以上你不能实现的功能，请友好提示用户：制作人阿涛并没有给我设计该功能"
                )
                .defaultFunctions("addCategoryImpl", "categoryListImpl", "deleteCategoryImpl","updateCategoryImpl")
                .build();
        this.imageModel = imageModel;
    }

    @GetMapping(value = "/chat")
    public Result<String> chat(@RequestParam String prompt) {
        // 使用 synchronized 关键字对这段代码进行加锁
        synchronized (this) {
            Map<String, Object> map = ThreadLocalUtil.get();
            Integer userId = (Integer) map.get("id");
            getIdUtil.setId(userId);
        }
        //获取用户聊天历史记录
        String history = aiService.list().toString();

        //获取用户所有的文章分类
        List<Category> cList = categoryService.list();
        List<String> c = new ArrayList<>();
        int i = 1;
        //用for循环遍历的方式得到其中的分类名称和分类别名
        for (Category category : cList) {
            c.add("第" + (i++) + "个分类的信息为：分类名称：" + category.getCategoryName() + "，分类别名：" + category.getCategoryAlias() + "。");
        }


        String answer = chatClient.prompt(prompt)
                .system(promptSystemSpec -> promptSystemSpec.param("current_date_time", LocalDateTime.now().toString()))
                .system(promptSystemSpec -> promptSystemSpec.param("history", history))
                .system(promptSystemSpec -> promptSystemSpec.param("allCategory", c.toString()))
                .call()
                .content();
        aiService.addMessage(prompt, answer);

        return success(answer);
    }

    /**
     * 使用ChatClient流式回答
     *
     * @param prompt
     * @return
     */
    @GetMapping(value = "/stream", produces = "text/html;charset=UTF-8")
    public Flux<String> stream(String prompt) {
        // 使用 synchronized 关键字对这段代码进行加锁
        synchronized (this) {
            Map<String, Object> map = ThreadLocalUtil.get();
            Integer userId = (Integer) map.get("id");
            getIdUtil.setId(userId);
        }
        
        //获取用户聊天历史记录
        String history = aiService.list().toString();

        //获取用户所有的文章分类
        List<Category> cList = categoryService.list();
        List<String> c = new ArrayList<>();
        int i = 1;
        //用for循环遍历的方式得到其中的分类名称和分类别名
        for (Category category : cList) {
            c.add("第" + (i++) + "个分类的信息为：分类名称：" + category.getCategoryName() + "，分类别名：" + category.getCategoryAlias() + "。");
        }

        // 创建原始响应流
        Flux<String> responseStream =
                chatClient.prompt(prompt)
                        .system(promptSystemSpec -> promptSystemSpec.param("current_date_time", LocalDateTime.now().toString()))
                        .system(promptSystemSpec -> promptSystemSpec.param("history", history))
                        .system(promptSystemSpec -> promptSystemSpec.param("allCategory", c.toString()))
                        .stream()
                        .content()
                        .cache(); // 使用cache操作符共享流

        // 异步保存完整内容到数据库
        responseStream.collect(Collectors.joining())
                .subscribe(fullResponse -> {
                    aiService.addStreamMessage(prompt, fullResponse);
                });
        return responseStream;
    }

    /**
     * 获取回答
     *
     * @return
     */
    @GetMapping("/message")
    public Result<List<AiMessage>> list() {
        List<AiMessage> ms = aiService.mList();
        return Result.success(ms);
    }

    /**
     * 图片回答
     *
     * @param prompt
     * @return
     */
    @GetMapping("/image")
    public Result<String> image(@RequestParam String prompt) {
        // 使用 synchronized 关键字对这段代码进行加锁
        synchronized (this) {
            Map<String, Object> map = ThreadLocalUtil.get();
            Integer userId = (Integer) map.get("id");
            getIdUtil.setId(userId);
        }

        String history = aiService.pList().toString();
        System.out.println(history);


        // 将历史记录嵌入到 prompt 中
        String enrichedPrompt = prompt + "\n历史记录如下: " + history;

        ImageOptions opt = ImageOptionsBuilder.builder()
                .width(512)
                .height(512)
                .build();

        // 调用imageModel生成图片
        String imageUrl = imageModel.call(new ImagePrompt(enrichedPrompt, opt)).getResult().getOutput().getUrl();
        String resultUrl = aiService.addPhoto(prompt, imageUrl);
        return Result.success(resultUrl);
    }

    /**
     * 返回前端的图片数据
     *
     * @return
     */
    @GetMapping("/imageList")
    public Result<List<AiPhotos>> imageList() {
        // 使用 synchronized 关键字对这段代码进行加锁
        synchronized (this) {
            Map<String, Object> map = ThreadLocalUtil.get();
            Integer userId = (Integer) map.get("id");
            getIdUtil.setId(userId);
        }
        List<AiPhotos> af = aiService.photoList();
        return Result.success(af);
    }

    /**
     * 删除文字聊天记录
     */
    @DeleteMapping("/deleteMessages")
    public Result deleteMessages() {
        // 使用 synchronized 关键字对这段代码进行加锁
        synchronized (this) {
            Map<String, Object> map = ThreadLocalUtil.get();
            Integer userId = (Integer) map.get("id");
            getIdUtil.setId(userId);
        }
        aiService.deleteMessages();
        return Result.success();
    }

    /**
     * 删除图片聊天记录
     *
     * @param
     * @return
     */
    @DeleteMapping("/deletePhotos")
    public Result deletePhotos() {
        // 使用 synchronized 关键字对这段代码进行加锁
        synchronized (this) {
            Map<String, Object> map = ThreadLocalUtil.get();
            Integer userId = (Integer) map.get("id");
            getIdUtil.setId(userId);
        }
        aiService.deletePhotos();
        return Result.success();
    }


}